package com.kamistoat.meimeimall.common.sharding.strategy;

import com.kamistoat.meimeimall.common.exception.BizCodeEnum;
import com.kamistoat.meimeimall.common.exception.RRException;
import com.kamistoat.meimeimall.common.sharding.Sharding;
import com.kamistoat.meimeimall.common.sharding.ShardingContext;
import com.kamistoat.meimeimall.common.sharding.properties.DatabaseProperties;

import java.util.HashMap;
import java.util.Map;

/**
 * 分库分表策略的抽象类，抽象出了一个公共属性和通用方法。
 */
public abstract class AbstractShardingStrategy implements ShardingStrategy {

    // 属性。记录数据源属性
    private static Map<String, DatabaseProperties> databasePropertiesMap = new HashMap<>();

    public static void setDatabasePropertiesMap(Map<String, DatabaseProperties> databasePropertiesMap) {
        AbstractShardingStrategy.databasePropertiesMap = databasePropertiesMap;
    }

    /**
     * 此方法用于确认分库名后建立链接，并返回确认的分表名。
     * 调用子类中的 calculateTableSuffix() 和 calculateDatabaseSuffix() 方法
     *
     * @param shardingKeyValue 分库分表key在实际方法中的值
     * @param sharding         @Sharding注解
     * @return 分表名
     */
    @Override
    public String constructConnectAndReturnTableName(String shardingKeyValue, Sharding sharding) {
        DatabaseProperties databaseProperties = databasePropertiesMap.get(sharding.databaseName());
        if (databaseProperties != null) {
            /**
             * 调用子类 calculateDatabaseSuffix() 计算子库序号
             */
            Integer databaseSuffix = calculateDatabaseSuffix(shardingKeyValue, sharding, databaseProperties);
            /**
             * 调用子类 calculateTableSuffix() 计算子表序号
             */
            Integer tableSuffix = calculateTableSuffix(shardingKeyValue, sharding, databaseProperties);
            /**
             * 拼接子库名称为 基础库名+主从标识+子库标号。
             * 放入 ShardingContext 中。之后在建立数据源链接时，Spring会从ShardingContext中取出子库名称，寻找对应的链接参数。
             * 并放入其他参数
             */
            ShardingContext.setShardingDatabase(sharding.databaseName() + ShardingContext.getMasterSalve() + databaseSuffix);
            ShardingContext.setShardingTable(sharding.tableName() + "_" + tableSuffix);
            ShardingContext.setMasterSalve(sharding.masterSlave());
            /**
             * 最后返回子表的名称： 基础表名_子表序号
             */
            return sharding.tableName() + "_" + tableSuffix;
        } else {
            throw new RRException(BizCodeEnum.SHARDING_DATABASES_NULL.getMessage(), BizCodeEnum.SHARDING_DATABASES_NULL.getCode());
        }
    }
}
